// import { t } from '@/i18n';

// import { usePlcWithOut } from '@/store/modules/plc';

import { isEqual, cloneDeep } from 'lodash';

import { v4 as uuidv4 } from 'uuid';

import { isConnectMqtt, mqttOptions } from './../dataOptions/options';

import { resolve, join } from 'path';

import { fork } from 'child_process';

// import { ipcRenderer } from 'electron';

// const { fork } = require('child_process');

let childProcessList: any = [];

let connectList: any = [];

// const { resolve, join } = require('path');

const isDev = process.env.NODE_ENV === 'development';

// const modbusStore = usePlcWithOut();

// (window as any).scriptPath = scriptPath;

// console.log(join(process.resourcesPath, 'app.asar.unpacked/modbus/index.js'));
// console.log(scriptPath);

// console.log('__dirname : ' + resolve('./modbus/index.js'));

let plcData: any = {};

let oldPlcData: any = {};

let mqttData: any = {};

let mqttTime: any = null;

let pending = false;

let isAddMqtt = false;

let electronWin = null;

const electronSendMessageFn = (data, dataType = 'message-data') => {
  if (electronWin && !electronWin.isDestroyed()) {
    const { webContents } = electronWin;

    webContents.send(dataType, data);
  }
};

const updateFn = () => {
  if (!pending) {
    pending = true;

    setTimeout(() => {
      if (plcData) {
        if (plcData['productionSpeedGet'] > 4000000000) {
          delete plcData['productionSpeedGet'];
        }

        if (!isEqual(plcData, oldPlcData)) {
          oldPlcData = cloneDeep(plcData);

          // const { webContents } = win as any;

          // console.log(webContents)

          // ipcRenderer.send('async-message',oldPlcData)

          electronSendMessageFn(oldPlcData, 'update-data');

          // webContents.send('update-data', oldPlcData);

          // console.log('数据更新了')
        }

        // modbusStore.updateNewData(plcData);

        mqttData = {
          ...mqttData,
          ...plcData,
        };
      }

      pending = false;
    }, 100);
  }

  // const modbusStore = useModbusWithOut();

  // modbusStore.updateNewData(plcData);

  return;
};

export const addChildProcessFn = (options, win) => {
  if (options) {
    const { plcId = null, connectType = null, addressList = null, addressObj = null } = options;

    electronWin = win;

    // const { webContents } = win as any;

    // const message = window['$message'];

    if (plcId && connectType && (addressList || addressObj)) {
      const scriptPath = isDev
        ? resolve(`./plcChildProcess/${options.connectType}/index.js`)
        : join(
            process.resourcesPath,
            `app.asar.unpacked/plcChildProcess/${options.connectType}/index.js`
          );

      console.log(scriptPath);

      const child = fork(scriptPath);

      child.on('data', (data) => {
        // console.log(options);
        console.log(`子进程${options.plcId}的console`, data.toString());
      });

      // console.log(child)

      const fnList: any = [];

      childProcessList.push({
        child,
        options,
        addressList,
        addressObj,
        plcId,
      });

      // console.log(JSON.stringify(options));

      child.send({
        type: 'init',
        options,
      });

      child.on('message', (obj: any) => {
        // console.log(obj);

        const {
          type = null,
          data = null,
          success = false,
          name = null,
          isTimeOut = false,
          err = null,
          msg = null,
          id = null,
        } = obj;

        if (type === 'write') {
          console.log(obj);
        }

        if (success) {
          if (type === 'read') {
            if (data && typeof data === 'object') {
              if (!plcData) {
                plcData = {};
              }

              plcData = { ...plcData, ...data };

              updateFn();
            } else {
              console.log(data);
            }
          } else if (type === 'write') {
            if (id && fnList && fnList.length) {
              fnList.every((item, key) => {
                if (item.id === id) {
                  item.fn && item.fn(data ? data : true);

                  fnList.splice(key, 1);

                  return false;
                }

                return true;
              });
            }

            electronSendMessageFn({ success: true, type: 'write' });

            // webContents.send('message-data', {success:true,type:'write'});

            // message.destroyAll();

            // message.success(t('common.tipMsg.writeSuccess'));
          } else if (type === 'isOnline') {
            // modbusStore.setIsOnLine(true);

            // modbusStore.removeNotOnlineNameFn(name);

            electronSendMessageFn({ success: true, type: 'isOnline', name });

            // webContents.send('message-data', {success:true,type:'isOnline',name});
          }
        } else {
          if (type === 'read') {
            if (isTimeOut) {
              // message.destroyAll();

              // message.error(`${name}读取超时`);

              electronSendMessageFn({ success: false, message: `${name}读取超时`, type: 'read' });

              // webContents.send('message-data', {success:false,message:`${name}读取超时`,type:'read'});

              // console.log(`${name}读取超时`);
            } else {
              // message.destroyAll();

              // message.error(`${name}读取报错`);

              electronSendMessageFn({
                success: false,
                message: `${name}读取报错`,
                err,
                msg,
                type: 'read',
              });

              // webContents.send('message-data', {success:false,message:`${name}读取报错`,err,msg,type:'read'});

              // console.log(`${name}读取报错`);

              // console.log('err', err);

              // console.log('msg', msg);
            }
          } else if (type === 'write') {
            if (id && fnList && fnList.length) {
              fnList.every((item, key) => {
                if (item.id === id) {
                  console.log(item);

                  item.fn && item.fn(false);

                  fnList.splice(key, 1);

                  return false;
                }

                return true;
              });
            }

            if (isTimeOut) {
              // message.destroyAll();

              // message.error(`${name}写入超时`);

              // console.log(`${name}写入超时`);

              electronSendMessageFn({ success: false, type: 'write', message: `${name}写入超时` });

              // webContents.send('message-data', {success:false,type:'write',message:`${name}写入超时`});
            } else {
              // message.destroyAll();

              // message.error(`${name}写入报错`);

              electronSendMessageFn({
                success: false,
                type: 'write',
                message: `${name}写入报错`,
                err,
                msg,
              });

              // webContents.send('message-data', {success:false,type:'write',message:`${name}写入报错`,err,msg});

              // console.log(`${name}写入报错`);

              // console.log('err', err);

              // console.log('msg', msg);
            }
          } else if (type === 'isOnline') {
            // modbusStore.setIsOnLine(false);

            // modbusStore.setNotOnlineNameFn(name);

            // webContents.send('message-data', { success: false, type: 'isOnline', name });

            electronSendMessageFn({ success: false, type: 'isOnline', name });
          }
        }
      });

      if (isConnectMqtt && !isAddMqtt && mqttOptions) {
        const scriptPath = isDev
          ? resolve(`./plcChildProcess/mqtt/index.js`)
          : join(process.resourcesPath, `app.asar.unpacked/plcChildProcess/mqtt/index.js`);

        const child = fork(scriptPath);

        childProcessList.push({
          child,
          options: mqttOptions,
          plcId: 'mqtt',
        });

        child.send({
          type: 'init',
          options: mqttOptions,
        });

        child.on('message', (obj: any) => {
          const { type = null, success = false } = obj;

          if (type === 'isOnline' && success) {
            if (mqttTime) {
              clearInterval(mqttTime);

              mqttTime = null;
            }

            mqttTime = setInterval(() => {
              if (JSON.stringify(mqttData) !== '{}') {
                // console.log()
                child.send({
                  type: 'write',
                  data: { data: mqttData },
                });

                console.log(mqttData);

                console.log('mqtt上传');

                mqttData = {};
              }
            }, mqttOptions.sendTime);
          }
        });

        isAddMqtt = true;
      }

      return {
        clickFn: (data, fn) => {
          // console.log(data);

          // console.log(child);

          // console.log(childProcessList);

          const id = uuidv4();

          if (fn) {
            fnList.push({
              id,
              fn,
              data,
            });
          }

          child.send({
            type: 'write',
            data: { writeObj: data, id },
          });
        },
      };
    }

    return {
      clickFn: () => {
        // message.error(t('common.tipMsg.writeError'));
      },
    };
  }

  return {
    clickFn: (obj, fn) => {
      console.log('plc对象没初始化成功，点击失败');

      console.log(obj);

      fn && fn(false);
    },
  };
};

export const deleteChildProcessFn = () => {
  if (mqttTime) {
    clearInterval(mqttTime);

    mqttTime = null;
  }

  if (childProcessList && childProcessList.length) {
    childProcessList.forEach((item) => {
      const { child = null } = item;

      if (child) {
        child.send({ type: 'delete' });

        child.kill();

        console.log('delete');
      }
    });
  }

  childProcessList = [];

  connectList = [];
};

export const connectFn = () => {
  if (childProcessList && childProcessList.length) {
    for (const item of childProcessList) {
      const { child = null } = item;

      child.send({ type: 'connect' });
    }
  }
};

const findFunIdObjFn = (addressList: any = [], funId: any = null) => {
  let obj: any = null;

  if (addressList && addressList.length) {
    addressList.every((item) => {
      const { funId: iFunId = null, list = [], bitFunIdObj = null } = item;

      if (funId === iFunId) {
        obj = item;

        return false;
      }

      if (bitFunIdObj) {
        for (const i in bitFunIdObj) {
          if (bitFunIdObj[i] === funId) {
            obj = {
              ...item,
              writeFunId: funId,
              bit: i,
            };

            return false;
          }
        }
      }

      if (list && list.length) {
        obj = findFunIdObjFn(list, funId);

        if (obj) {
          return false;
        }
      }

      return true;
    });
  }

  return obj;
};

export const connectInitFn = async (list: any = [], win) => {
  // const message = window['$message'];

  deleteChildProcessFn();

  // const { webContents } = win;

  if (list && list.length) {
    try {
      for (let i = 0; i < list.length; i++) {
        const { clickFn = null } = await addChildProcessFn(list[i], win);

        connectList.push({
          ...list[i],
          clickFn,
        });
      }

      // console.log(connectList);

      return {
        clickFn: (cList = [], clickPlcId = null) => {
          console.log(JSON.parse(JSON.stringify(cList)));

          let fList: any = cList;

          if (Object.prototype.toString.call(fList) === '[object Object]') {
            fList = [fList];
          }

          if (clickPlcId) {
            const plc = connectList.find((item) => item.plcId === clickPlcId);

            if (plc) {
              const { clickFn = null, connectType = null } = plc;

              if (clickFn) {
                if (connectType === 'modbus') {
                  clickFn(fList[0], fList[0].fn);
                } else {
                  console.log('该plc连接方式暂无兼容该方法');

                  // message.error(t('common.tipMsg.writeError'));

                  electronSendMessageFn({
                    success: false,
                    type: 'write',
                    message: '该plc连接方式暂无兼容该方法',
                  });

                  // webContents.send('message-data', {success:false,type:'write',message:'该plc连接方式暂无兼容该方法'});

                  return false;
                }
              } else {
                // console.log('该plc没有写入方法');

                electronSendMessageFn({
                  success: false,
                  type: 'write',
                  message: '该plc没有写入方法',
                });

                // webContents.send('message-data', {success:false,type:'write',message:'该plc没有写入方法'});

                // message.error(t('common.tipMsg.writeError'));

                return false;
              }
            } else {
              // console.log('找不到对应的plc');

              electronSendMessageFn({ success: false, type: 'write', message: '找不到对应的plc' });

              // webContents.send('message-data', {success:false,type:'write',message:'找不到对应的plc'});

              // message.error(t('common.tipMsg.writeError'));

              return false;
            }
          } else {
            if (fList && fList.length) {
              let dataObjList: any = null;

              for (const item of fList) {
                const {
                  plcId = null,
                  funId = null,
                  value = null,
                  fn = null,
                  type = null,
                  offsetId = null,
                } = item;

                if (plcId) {
                  const plc = connectList.find((cItem) => cItem.plcId === plcId);

                  if (plc && funId) {
                    const {
                      connectType = null,
                      clickFn = null,
                      addressList = [],
                      addressObj = null,
                    } = plc;

                    if (connectType === 's7') {
                      let newVal = value;

                      if (!dataObjList) {
                        dataObjList = [];

                        if (funId in addressObj) {
                          if (addressObj[funId].includes(',X')) {
                            newVal = Number(newVal) === 1;
                          }
                        }

                        dataObjList.push({
                          plcId,
                          clickFn,
                          data: { [funId]: newVal },
                        });
                      } else {
                        const plcObj = dataObjList.find((item) => item.plcId === plcId);

                        if (funId in addressObj) {
                          if (addressObj[funId].includes(',X')) {
                            newVal = Number(newVal) === 1;
                          }
                        }

                        if (plcObj) {
                          plcObj['data'][funId] = newVal;
                        } else {
                          dataObjList.push({
                            plcId,
                            data: { [funId]: newVal },
                          });
                        }
                      }
                    } else if (connectType === 'modbus' || connectType === 'fins') {
                      if (clickFn) {
                        if (type && offsetId) {
                          clickFn(item, fn);
                        } else if (addressList && addressList.length) {
                          const obj = findFunIdObjFn(addressList, funId);

                          if (obj) {
                            const {
                              type = null,
                              leng = null,
                              bit = null,
                              bitFunIdObj = null,
                              funId: oFunId = null,
                            } = obj;

                            let code = 5;

                            switch (type) {
                              case 'bool':
                                code = 5;
                                break;
                              case 'int':
                              case 'int8':
                              case 'int16':
                              case 'uint16':
                              case 'enum':
                                code = 6;
                                break;
                              case 'int32':
                              case 'uint32':
                              case 'float':
                              case 'real':
                              case 'int64':
                              case 'uint64':
                              case 'double':
                                code = 10;
                                break;
                              case 'bit':
                              case 'bitOne':
                                if (leng === 2) {
                                  code = 6;
                                } else if (leng === 4) {
                                  code = 10;
                                }
                                break;

                              default:
                                break;
                            }

                            if ((type === 'bit' || type === 'bitOne') && bitFunIdObj && bit !== null) {
                              const newValue = cloneDeep(plcData[oFunId]) || null;

                              if (
                                newValue &&
                                Object.prototype.toString.call(newValue) === '[object Array]'
                              ) {
                                newValue[bit] = value.toString();

                                if (type === 'bitOne') {
                                  for (const b in bitFunIdObj) {
                                    if (b !== bit) {
                                      newValue[b] = '0';
                                    }
                                  }
                                }

                                clickFn(
                                  {
                                    ...obj,
                                    addr: obj.offsetId,
                                    code,
                                    value: newValue,
                                  },
                                  fn
                                );
                              }
                            } else {
                              clickFn({ ...obj, addr: obj.offsetId, code, value }, fn);
                            }
                          } else {
                            // console.log(`该plc找不到funId:${funId}`);

                            electronSendMessageFn({
                              success: false,
                              type: 'write',
                              message: `该plc找不到funId:${funId}`,
                            });

                            // webContents.send('message-data', {success:false,type:'write',message:`该plc找不到funId:${funId}`});

                            // message.error(t('common.tipMsg.writeError'));
                          }
                        } else {
                          // console.log(`该写入数据有误`, item);

                          electronSendMessageFn({
                            success: false,
                            type: 'write',
                            message: `该写入数据有误`,
                            err: item,
                          });

                          // webContents.send('message-data', {success:false,type:'write',message:`该写入数据有误`,err:item});

                          // message.error(t('common.tipMsg.writeError'));
                        }
                      } else {
                        console.log('该plc没有写入方法');

                        electronSendMessageFn({
                          success: false,
                          type: 'write',
                          message: `该plc没有写入方法`,
                        });

                        // webContents.send('message-data', {success:false,type:'write',message:`该plc没有写入方法`});

                        // message.error(t('common.tipMsg.writeError'));
                      }
                    } else if (connectType === 'opcua') {
                      const obj = addressList.find((item) => item.funId === funId);

                      if (obj) {
                        if (obj.type) {
                          let newVal = value;

                          if (obj.type === 'Boolean') {
                            newVal = Number(newVal) === 1;
                          }

                          if (!dataObjList) {
                            dataObjList = [];

                            dataObjList.push({
                              plcId,
                              clickFn,
                              data: [{ ...obj, value: newVal }],
                            });
                          } else {
                            const plcObj = dataObjList.find((item) => item.plcId === plcId);

                            if (plcObj) {
                              dataObjList['data'].push({
                                ...obj,
                                value: newVal,
                              });
                            } else {
                              dataObjList.push({
                                plcId,
                                clickFn,
                                data: [{ ...obj, value: newVal }],
                              });
                            }
                          }
                        } else {
                          // console.log(`该funId:${funId}没有配置写入类型`);

                          electronSendMessageFn({
                            success: false,
                            type: 'write',
                            message: `该funId:${funId}没有配置写入类型`,
                          });

                          // webContents.send('message-data', {success:false,type:'write',message:`该funId:${funId}没有配置写入类型`});

                          // message.error(t('common.tipMsg.writeError'));
                        }
                      } else {
                        // console.log(`该plc找不到funId:${funId}`);
                        electronSendMessageFn({
                          success: false,
                          type: 'write',
                          message: `该plc找不到funId:${funId}`,
                        });
                        // webContents.send('message-data', {success:false,type:'write',message:`该plc找不到funId:${funId}`});

                        // message.error(t('common.tipMsg.writeError'));
                      }
                    }
                  } else {
                    if (!plc) {
                      console.log('找不到对应的plc');

                      electronSendMessageFn({
                        success: false,
                        type: 'write',
                        message: '找不到对应的plc',
                      });

                      // webContents.send('message-data', {success:false,type:'write',message:'找不到对应的plc'});

                      // message.error(t('common.tipMsg.writeError'));

                      return false;
                    }

                    if (!funId) {
                      // console.log('没有funId');
                      electronSendMessageFn({
                        success: false,
                        type: 'write',
                        message: '没有funId',
                      });

                      // webContents.send('message-data', {success:false,type:'write',message:'没有funId'});

                      // message.error(t('common.tipMsg.writeError'));

                      return false;
                    }
                  }
                } else if (funId) {
                  const isClick = !connectList.every((cItem) => {
                    const {
                      connectType = null,
                      clickFn = null,
                      addressList = [],
                      addressObj = {},
                      plcId = null,
                    } = cItem;

                    if (connectType === 's7') {
                      // console.log(value)
                      if (addressObj) {
                        if (funId in addressObj) {
                          let newVal = value;

                          if (addressObj[funId].includes(',X')) {
                            newVal = Number(newVal) === 1;
                          }

                          if (!dataObjList) {
                            dataObjList = [];

                            dataObjList.push({
                              plcId,
                              clickFn,
                              data: { [funId]: newVal },
                            });
                          } else {
                            const plcObj = dataObjList.find((item) => item.plcId === plcId);

                            if (plcObj) {
                              plcObj['data'][funId] = newVal;
                            } else {
                              dataObjList.push({
                                plcId,
                                data: { [funId]: newVal },
                              });
                            }
                          }

                          return false;
                        }
                      }
                    } else if (connectType === 'modbus' || connectType === 'fins') {
                      if (addressList && addressList.length) {
                        const obj = findFunIdObjFn(addressList, funId);

                        if (obj) {
                          if (clickFn) {
                            const {
                              type = null,
                              leng = null,
                              bitFunIdObj = null,
                              bit = null,
                              funId: oFunId = null,
                            } = obj;

                            let code = 5;

                            switch (type) {
                              case 'bool':
                                code = 5;
                                break;
                              case 'int':
                              case 'int8':
                              case 'int16':
                              case 'uint16':
                              case 'enum':
                                code = 6;
                                break;
                              case 'int32':
                              case 'uint32':
                              case 'float':
                              case 'real':
                              case 'int64':
                              case 'uint64':
                              case 'double':
                                code = 10;
                                break;
                              case 'bit':
                              case 'bitOne':
                                if (leng === 2) {
                                  code = 6;
                                } else if (leng === 4) {
                                  code = 10;
                                }
                                break;

                              default:
                                break;
                            }

                            // console.log(code)

                            if ((type === 'bit' || type === 'bitOne') && bitFunIdObj && bit !== null) {
                              const newValue = cloneDeep(plcData[oFunId]) || null;

                              if (
                                newValue &&
                                Object.prototype.toString.call(newValue) === '[object Array]'
                              ) {
                                newValue[bit] = value.toString();

                                if (type === 'bitOne') {
                                  for (const b in bitFunIdObj) {
                                    if (b !== bit) {
                                      newValue[b] = '0';
                                    }
                                  }
                                }

                                clickFn(
                                  {
                                    ...obj,
                                    addr: obj.offsetId,
                                    code,
                                    value: newValue,
                                  },
                                  fn
                                );
                              }
                            } else {
                              clickFn({ ...obj, addr: obj.offsetId, code, value }, fn);
                            }
                          } else {
                            // console.log('该plc没有写入方法');

                            electronSendMessageFn({
                              success: false,
                              type: 'write',
                              message: '该plc没有写入方法',
                            });

                            // webContents.send('message-data', {success:false,type:'write',message:'该plc没有写入方法'});

                            // message.error(t('common.tipMsg.writeError'));
                          }

                          return false;
                        }
                      }
                    } else if (connectType === 'opcua') {
                      if (addressList && addressList.length) {
                        const obj = findFunIdObjFn(addressList, funId);

                        if (obj) {
                          if (obj.type) {
                            let newVal = value;

                            if (obj.type === 'Boolean') {
                              newVal = Number(newVal) === 1;
                            }

                            if (!dataObjList) {
                              dataObjList = [];

                              dataObjList.push({
                                plcId,
                                clickFn,
                                data: [{ ...obj, value: newVal }],
                              });
                            } else {
                              const plcObj = dataObjList.find((item) => item.plcId === plcId);

                              if (plcObj) {
                                plcObj['data'].push({ ...obj, value });
                              } else {
                                dataObjList.push({
                                  plcId,
                                  clickFn,
                                  data: [{ ...obj, value: newVal }],
                                });
                              }
                            }
                          } else {
                            // console.log(`该funId:${funId}没有配置写入类型`);

                            electronSendMessageFn({
                              success: false,
                              type: 'write',
                              message: `该funId:${funId}没有配置写入类型`,
                            });

                            // webContents.send('message-data', {success:false,type:'write',message:`该funId:${funId}没有配置写入类型`});

                            // message.error(t('common.tipMsg.writeError'));
                          }

                          return false;
                        }

                        return true;
                      }
                    }

                    return true;
                  });

                  if (!isClick) {
                    // console.log(`该写入数据有误`, item);

                    electronSendMessageFn({
                      success: false,
                      type: 'write',
                      message: `该写入数据有误`,
                      err: item,
                    });

                    // webContents.send('message-data', {success:false,type:'write',message:`该写入数据有误`,err:item});

                    // message.error(t('common.tipMsg.writeError'));
                  }
                } else {
                  // console.log(`该写入数据有误`, item);

                  electronSendMessageFn({
                    success: false,
                    type: 'write',
                    message: `该写入数据有误`,
                    err: item,
                  });

                  // webContents.send('message-data', {success:false,type:'write',message:`该写入数据有误`,err:item});

                  // message.error(t('common.tipMsg.writeError'));
                }
              }

              if (dataObjList && dataObjList.length) {
                for (const item of dataObjList) {
                  const { clickFn = null, data = null } = item;

                  if (clickFn) {
                    clickFn(data);
                  } else {
                    // console.log('该plc没有写入方法');

                    electronSendMessageFn({
                      success: false,
                      type: 'write',
                      message: `该plc没有写入方法`,
                    });

                    // webContents.send('message-data', {success:false,type:'write',message:`该plc没有写入方法`});

                    // message.error(t('common.tipMsg.writeError'));
                  }
                }
              }
            }
          }
        },
      };
    } catch (e) {
      console.log(e);
    }
  }

  return {
    clickFn: () => {
      // message.error(t('common.tipMsg.writeError'));

      electronSendMessageFn({ success: false, type: 'write', message: `没有连接plc` });

      // webContents.send('message-data', {success:false,type:'write',message:`没有连接plc`});

      // console.log('没有连接plc');
    },
  };
};

// setTimeout(() => {
//   window.onbeforeunload = function (_e) {
//     deleteChildProcessFn();
//     // window.location.reload();
//   };

//   (window as any).childProcessList = childProcessList;

//   (window as any).deleteChildProcessFn = deleteChildProcessFn;
// }, 500);

export const getPlcDataFn = () => {
  oldPlcData = {};
};
